﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Interactivity;
using nRoute.ApplicationServices;
using nRoute.Components.Composition;
using nRoute.ViewServices;
#if (WINRT)
using Windows.UI.Xaml;
using nRoute.Behaviors.Interactivity;
using Windows.UI.Xaml.Data;
#endif

namespace nRoute.Behaviors
{
    public class ViewServiceBehaviorBase<T>
        : Behavior<T>
        where
#if (WINRT)
            T : FrameworkElement
#else
            T : DependencyObject
#endif
    {
        private const string VIEWSERIVCENAME_ALREADY_SPECIFIED = "Name ('{0}') for ViewService has already been specified. It cannot be set/registered twice.";
        private const string VIEWSERIVCETYPE_ALREADY_SPECIFIED = "ViewService type '{0}' has already been specified. It cannot be set/registered twice.";

        [Category("Common Properties")]
        public static readonly DependencyProperty ViewServiceTypeProperty =
            DependencyProperty.Register("ViewServiceType", typeof(Type), typeof(ViewServiceBehaviorBase<T>),
            new PropertyMetadata(Utilities.Compatability.DP_UNSET_VALUE, OnViewServiceTypeChanged));

        [Category("Common Properties")]
        public static readonly DependencyProperty ViewServiceNameProperty =
            DependencyProperty.Register("ViewServiceName", typeof(string), typeof(ViewServiceBehaviorBase<T>),
            new PropertyMetadata(Utilities.Compatability.DP_UNSET_VALUE, OnViewServiceNameChanged));

        [Category("Common Properties")]
        public static readonly DependencyProperty IsDefaultProperty =
            DependencyProperty.Register("IsDefault", typeof(bool), typeof(ViewServiceBehaviorBase<T>),
            new PropertyMetadata(false));

#region Properties

        [Category("Common Properties")]
        protected virtual Type ViewServiceType
        {
            get { return (Type)GetValue(ViewServiceTypeProperty); }
            set { SetValue(ViewServiceTypeProperty, value); }
        }

        [Category("Common Properties")]
        protected virtual string ViewServiceName
        {
            get { return Convert.ToString(GetValue(ViewServiceNameProperty)); }
            set { SetValue(ViewServiceNameProperty, value); }
        }

        [Category("Common Properties")]
        protected virtual bool IsDefault
        {
            get { return Convert.ToBoolean(GetValue(IsDefaultProperty)); }
            set { SetValue(IsDefaultProperty, value); }
        }

#endregion

#region Overrides

        protected override void OnAttached()
        {
            base.OnAttached();

            if (this.ViewServiceType != null && this.AssociatedObject != null)
            {
                var _catalog = nRouteApplicationService.Current.ResourceCatalog.GetResource<IResourceCatalogEx>();
                if (_catalog != null)
                {
                    if (string.IsNullOrEmpty(ViewServiceName)) this.ViewServiceName = Guid.NewGuid().ToString();    // needs to be specified, so we can unregister it later
                    _catalog.CatalogResource(this.ViewServiceType, this.ViewServiceName, new StaticResourceLocator(this.AssociatedObject), this.IsDefault);
                }
            }
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            if (this.ViewServiceType != null && !string.IsNullOrEmpty(ViewServiceName) && this.AssociatedObject != null)
            {
                var _catalog = nRouteApplicationService.Current.ResourceCatalog.GetResource<IResourceCatalogEx>();
                if (_catalog != null)
                {
                    _catalog.UncatalogResource(this.ViewServiceType, this.ViewServiceName);
                }
            }
        }

#endregion

#region Handlers

        protected void UpdateViewServiceName(string oldName, string newName)
        {
            if (!string.IsNullOrEmpty(oldName))
            {
                throw new InvalidOperationException(string.Format(VIEWSERIVCENAME_ALREADY_SPECIFIED, oldName));
            }
        }

        protected void UpdateViewServiceType(Type oldType, Type newType)
        {
            if (oldType != null)
            {
                throw new InvalidOperationException(string.Format(VIEWSERIVCENAME_ALREADY_SPECIFIED, oldType.FullName));
            }
        }

        private static void OnViewServiceNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ViewServiceBehaviorBase<T>)d).UpdateViewServiceName(Convert.ToString(e.OldValue), Convert.ToString(e.NewValue));
        }

        private static void OnViewServiceTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ViewServiceBehaviorBase<T>)d).UpdateViewServiceType((Type)e.OldValue, (Type)e.NewValue);
        }

#endregion

    }
}